package com.hframe.http.servlet;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.hframe.Json.JsonToData;
import com.hframe.data.Base;
import com.hframe.data.DRef;
import com.hframe.filter.PageSkipFilter;
import com.hframe.param.ParamToData;
import com.hframe.utils.SrteamUtil;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.util.ParameterMap;
import org.apache.log4j.Logger;
import org.apache.tomcat.util.http.Parameters;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.lang.reflect.Field;
import java.util.*;


public class HttpSkipServletRequest extends HttpServletRequestWrapper {
    private static Logger log = Logger.getLogger(HttpSkipServletRequest.class);
    private List<FileItem> fileList = null;
    private String debugJson = null;
    private boolean parsedParams = false;

    public HttpSkipServletRequest(HttpServletRequest request) {
        super(request);
    }

    public boolean isSkip() {
        return null != getAttribute(PageSkipFilter.SkipTag);
    }

    public String getSkipUrl() {
        return (String) getAttribute(PageSkipFilter.SkipTag);
    }

    public void setDebugJson(String debugJson) {
        this.debugJson = debugJson;
    }


    public JsonElement getJson() throws Exception {
        if (null != debugJson)
            return new JsonParser().parse(debugJson);

        String type = new SrteamUtil().getInputString(super.getInputStream());
        return new JsonParser().parse(type);
    }

    public List<FileItem> getFileList() {
        if (null == fileList) {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setHeaderEncoding("UTF-8");
            try {
                fileList = upload.parseRequest(new ServletRequestContext((HttpServletRequest) getRequest()));
            } catch (FileUploadException e) {
                log.error(e, e);
            }
        }
        return fileList;
    }

    private Parameters getParameters() {
        try {

            RequestFacade facade = (RequestFacade) getRequest();
            Field field = facade.getClass().getDeclaredField("request");
            field.setAccessible(true);
            Request request = (Request) field.get(facade);
            return request.getCoyoteRequest().getParameters();

        } catch (Exception e) {
            log.error(e, e);
        }
        return null;
    }


    private void parseParameters() {
        if (!this.parsedParams) {
            String type = super.getContentType();
            if (null != type && 0 == type.indexOf("multipart/form-data;")) {

                DiskFileItemFactory factory = new DiskFileItemFactory();
                ServletFileUpload upload = new ServletFileUpload(factory);
                upload.setHeaderEncoding("UTF-8");

                Parameters parameters = getParameters();
                if (null != parameters) {
                    try {
                        getFileList();
                        for (FileItem item : fileList) {
                            if (item.isFormField()) {
                                parameters.addParameter(item.getFieldName(), item.getString("UTF-8"));
                            }
                        }
                    } catch (Exception e) {
                        log.error(e, e);
                    }
                }
            }
            this.parsedParams = true;
        }
    }


    @Override
    public String getParameter(String name) {
        parseParameters();
        return super.getParameter(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        parseParameters();
        return super.getParameterMap();
    }

    @Override
    public Enumeration<String> getParameterNames() {
        parseParameters();
        return super.getParameterNames();
    }

    @Override
    public String[] getParameterValues(String name) {
        parseParameters();
        return super.getParameterValues(name);
    }


    public <T extends Base> T getData(Class<T> dataClass) throws Exception {
        T data = dataClass.newInstance();
        JsonToData.convert(getJson(), data);
        return data;
    }

    public <T extends Base> T getData(T data) throws Exception {
        JsonToData.convert(getJson(), data);
        return data;
    }

    public <T extends DRef> T getParameter(Class<T> dataClass) throws Exception {
        T data = dataClass.newInstance();
        ParamToData.convert(getParameterMap(), data);
        return data;
    }

    public <T extends DRef> T getParameter(T data) throws Exception {
        ParamToData.convert(getParameterMap(), data);
        return data;
    }

    public void setSkipUrl(String skipUrl) {
        setAttribute(PageSkipFilter.SkipTag, skipUrl);
    }


}
